module Local () where

import Tipos
import Combo
import Pedido

data Local = L [(Bebida,Int)] [(Hamburguesa,Int)] [Empleado]| VenderPedido Pedido Local | Sancion Empleado Energia Local
	deriving (Show)

nuevoL :: [Bebida] -> [Hamburguesa] -> [Empleado] -> Local
nuevoL bebidas sanguches empleados = (L stockBebidaCantidadSinRepeticion stockSanguchesSinRepeticion empleados)
	where	stockBebidaCantidadSinRepeticion = (sacarRepetidos (listaStock bebidas) bebidas)
		stockSanguchesSinRepeticion = (sacarRepetidos (listaStock sanguches) sanguches)

--Aux
listaStock :: Eq a => [a] -> [(a,Int)]
listaStock [] = []
listaStock (b:bs) = (b, cantApariciones b (b:bs)):listaStock bs

--Aux
sacarRepetidos :: Eq a => [(a,Int)] -> [a] -> [(a,Int)]
sacarRepetidos [] _ = []
sacarRepetidos ((x,y):ls) sb 
	|y == cantApariciones x sb = (x,y):sacarRepetidos ls sb
	|otherwise = sacarRepetidos ls sb

--Aux
cantApariciones :: Eq a => a -> [a] -> Int
cantApariciones b [] = 0 
cantApariciones b (be: bs)
	|b == be = 1 + (cantApariciones b bs)
	|otherwise = cantApariciones b bs


stockBebidasL :: Local -> Bebida -> Int
stockBebidasL local bebida = actualizarStockB local bebida (totalBebidasVendidas (bebidasVendidas local))

--Aux
actualizarStockB :: Local -> Bebida -> [(Bebida,Int)] -> Int
actualizarStockB (L bs1 hs es) b1 [] = stockInicialB (L bs1 hs es) b1
actualizarStockB (L bs1 hs es) b1 ((b2,n):bs)
	|b1 == b2 = (stockInicialB (L bs1 hs es) b1) - n
	|otherwise = actualizarStockB (L bs1 hs es) b1 bs
actualizarStockB (Sancion empleado energia local) bebida lista = actualizarStockB local bebida lista
actualizarStockB (VenderPedido pedido local) bebida lista = actualizarStockB local bebida lista 

--Aux
bebidasVendidas :: Local -> [(Bebida,Int)]
bebidasVendidas local = bebidasVendidas2 (ventasL local)

--Aux
bebidasVendidas2 :: [Pedido] -> [(Bebida,Int)]
bebidasVendidas2 [] = []
bebidasVendidas2 (p:ps) = stockBebSinRepes ++ bebidasVendidas2 ps
	where	stockBebSinRepes = (sacarRepetidos (listaStock (bebidasDelPedido p (combosP p))) (bebidasDelPedido p (combosP p)))

--Aux
totalBebidasVendidas :: [(Bebida,Int)] -> [(Bebida,Int)]
totalBebidasVendidas [] = []
totalBebidasVendidas [x] = [x]
totalBebidasVendidas ((b1,n):(b2,m):bs)
	|cantApariciones b1 listaBebidaStock == 1 = (b1,n):totalBebidasVendidas ((b2,m):bs)
	|b1==b2 = totalBebidasVendidas ((b1,n+m):bs)
	|otherwise = totalBebidasVendidas (((b1,n):bs)++[(b2,m)])
	where	listaBebidaStock = (bebidasDe ((b1,n):(b2,m):bs))
--Aux
bebidasDe :: [(Bebida,Int)] -> [Bebida]
bebidasDe [] = []
bebidasDe ((b,n):bs) = b : bebidasDe bs

--Aux
stockInicialB :: Local -> Bebida -> Int
stockInicialB (L [] _ _) bebida = 0
stockInicialB (L ((b,n):bs) hs es) bebida
	|bebida == b = n
	|otherwise = stockInicialB (L bs hs es) bebida
stockInicialB (VenderPedido p l) bebida = stockInicialB l bebida
stockInicialB (Sancion empleado energia l) bebida = stockInicialB l bebida


--Aux
bebidasDelPedido :: Pedido -> [Combo] -> [Bebida]
bebidasDelPedido p [] = []
bebidasDelPedido p (x:xs) = bebidaC x : bebidasDelPedido p xs

stockSandwichesL :: Local -> Hamburguesa -> Int
stockSandwichesL local sanguche = actualizarStockS local sanguche (totalSanguchesVendidos (sanguchesVendidos local))

--Aux
actualizarStockS :: Local -> Hamburguesa -> [(Hamburguesa,Int)] -> Int
actualizarStockS (L bs hs1 es) h1 [] = stockInicialS (L bs hs1 es) h1
actualizarStockS (L bs hs1 es) h1 ((h2,n):hs)
	|h1 == h2 = (stockInicialS (L bs hs1 es) h1) - n
	|otherwise = actualizarStockS (L bs hs1 es) h1 hs
actualizarStockS (Sancion empleado energia local) sanguche lista = actualizarStockS local sanguche lista
actualizarStockS (VenderPedido pedido local) sanguche lista = actualizarStockS local sanguche lista

--Aux
sanguchesVendidos :: Local -> [(Hamburguesa,Int)]
sanguchesVendidos local = sanguchesVendidos2 (ventasL local)

--aux
sanguchesVendidos2 :: [Pedido] -> [(Hamburguesa,Int)]
sanguchesVendidos2 [] = []
sanguchesVendidos2 (p:ps) = stockSanguchesSinRepeticion ++ sanguchesVendidos2 ps	
	where	stockSanguchesSinRepeticion = (sacarRepetidos (listaStock (sanguchesDelPedido p (combosP p))) (sanguchesDelPedido p (combosP p)))

--Aux
totalSanguchesVendidos :: [(Hamburguesa,Int)] -> [(Hamburguesa,Int)]
totalSanguchesVendidos [] = []
totalSanguchesVendidos [x] = [x]
totalSanguchesVendidos ((h1,n):(h2,m):hs)
	|cantApariciones h1 listaSangucheStock == 1 = (h1,n):totalSanguchesVendidos ((h2,m):hs)
	|h1==h2 = totalSanguchesVendidos ((h1,n+m):hs)
	|otherwise = totalSanguchesVendidos (((h1,n):hs)++[(h2,m)])
	where	listaSangucheStock = (sanguchesDe ((h1,n):(h2,m):hs))

--Aux
sanguchesDe :: [(Hamburguesa,Int)] -> [Hamburguesa]
sanguchesDe [] = []
sanguchesDe ((h,n):hs) = h : sanguchesDe hs

--Aux
stockInicialS :: Local -> Hamburguesa -> Int
stockInicialS (L _ [] _) sanguche = 0
stockInicialS (L bs ((h,n):hs) es) sanguche
	|sanguche == h = n
	|otherwise = stockInicialS (L bs hs es) sanguche
stockInicialS (VenderPedido p l) sanguche = stockInicialS l sanguche
stockInicialS (Sancion empleado energia l) sanguche = stockInicialS l sanguche


--Aux
sanguchesDelPedido :: Pedido -> [Combo] -> [Hamburguesa]
sanguchesDelPedido p [] = []
sanguchesDelPedido p (x:xs) = sandwichC x : sanguchesDelPedido p xs

bebidasDelLocal :: Local -> [Bebida]
bebidasDelLocal (L [] _ _) = []
bebidasDelLocal (L ((b,n):bs) hs es) = b:bebidasDelLocal (L bs hs es)

sandwichesDelLocal :: Local -> [Hamburguesa]
sandwichesDelLocal (L _ [] _) = []
sandwichesDelLocal (L bs ((h,n):hs) es) = h:sandwichesDelLocal (L bs hs es)

empleadosL :: Local -> [Empleado]
empleadosL l = soloEmpleados l (empleadosAlInicio l)

--aux
empleadosAlInicio :: Local -> [Empleado]
empleadosAlInicio (L _ _ le) = le
empleadosAlInicio (VenderPedido _ l) = empleadosAlInicio l
empleadosAlInicio (Sancion _ _ l) = empleadosAlInicio l

--aux
soloEmpleados :: Local -> [Empleado] -> [Empleado]
soloEmpleados l [] = []
soloEmpleados l (x:xs)
	|energiaEmpleadoL l x < 0 = soloEmpleados l xs
	|otherwise = x:soloEmpleados l xs

desempleadosL :: Local -> [Empleado]
desempleadosL l = soloDesempleados l (empleadosAlInicio l)

--aux
soloDesempleados :: Local -> [Empleado] -> [Empleado]
soloDesempleados l [] = []
soloDesempleados l (x:xs)
	|energiaEmpleadoL l x >= 0 = soloDesempleados l xs
	|otherwise = x:soloDesempleados l xs

energiaEmpleadoL :: Local -> Empleado -> Int
energiaEmpleadoL (L _ _ _) empleado = 100
energiaEmpleadoL (Sancion e energia l) empleado
	|e==empleado = (energiaEmpleadoL l empleado) - energia
	|otherwise = energiaEmpleadoL l empleado
energiaEmpleadoL (VenderPedido p l) empleado
	|atendioP p == empleado = (energiaEmpleadoL l empleado) - dificultadP p
	|otherwise = energiaEmpleadoL l empleado

ventasL :: Local -> [Pedido]
ventasL (L _ _ _) = []
ventasL (Sancion _ _ l) = ventasL l
ventasL (VenderPedido p l) = p:ventasL l

unaVentaCadaUno :: Local -> Bool
unaVentaCadaUno local = unaVentaCadaUno' (primerasApariciones losQueVendieron) losQueVendieron
	where	losQueVendieron = (empleadosQueVendieron (ventasL local) (empleadosL local) (empleadosL local))

--Aux
unaVentaCadaUno' :: [Empleado] -> [Empleado] -> Bool
unaVentaCadaUno' xs [] = True
unaVentaCadaUno' (x:xs) (y:ys)
	|esPrefijo (x:xs) (y:ys) = unaVentaCadaUno' (x:xs) (sacarPrefijo (x:xs) (y:ys))
	|otherwise = x==y && unaVentaCadaUno' xs ys

--Aux
empleadosQueVendieron :: [Pedido] -> [Empleado] -> [Empleado] -> [Empleado]
empleadosQueVendieron [] _ _ = []
empleadosQueVendieron (p:ps) empleadosDelLocal [] = empleadosQueVendieron ps empleadosDelLocal empleadosDelLocal 
empleadosQueVendieron (p:ps) empleadosDelLocal (empleado:posiblesVendedores)
	|atendioP p == empleado = empleado:empleadosQueVendieron ps empleadosDelLocal empleadosDelLocal
	|otherwise = empleadosQueVendieron (p:ps) empleadosDelLocal posiblesVendedores

--Aux
esPrefijo :: Eq a => [a] -> [a] -> Bool
esPrefijo [] _ = True
esPrefijo xs [] = False
esPrefijo (x:xs) (y:ys) = x==y && esPrefijo xs ys

--Aux
sacarPrefijo :: [a] -> [a] -> [a]
sacarPrefijo [] ys = ys
sacarPrefijo (x:xs) (y:ys) = sacarPrefijo xs ys

--Aux
primerasApariciones :: Eq a => [a] -> [a]
primerasApariciones lista = primerasApariciones' [] lista

--Aux
primerasApariciones' :: Eq a => [a] -> [a] -> [a]
primerasApariciones' xs [] = xs
primerasApariciones' xs (y:ys)
	|elem y xs == False = primerasApariciones' (xs++[y]) ys
	|otherwise = primerasApariciones' xs ys

venderL :: Local -> Pedido -> Local
venderL local pedido 
		|energiaEmpleadoL local (atendioP pedido) >= dificultadP pedido = VenderPedido pedido local  
		|otherwise = sancionL local (atendioP pedido) (dificultadP pedido)

		
candidatosAEmpleadosDelMes :: Local -> [Empleado]
candidatosAEmpleadosDelMes l = candidatosListos
	where	candidatosListos = filtroPorCombo l (filtroPorVenta l (empleadosL l))

--aux
filtroPorVenta :: Local -> [Empleado] -> [Empleado]
filtroPorVenta l [] = []
filtroPorVenta l (e:es)
	|maxVentas l (empleadosL l) == numVentas l e = e:(filtroPorVenta l es)
	|otherwise = filtroPorVenta l es

--aux
maxVentas :: Local -> [Empleado] -> Int
maxVentas l (e:[]) = numVentas l e
maxVentas l (x:y:es) 
	|numVentas l x >= numVentas l y = maxVentas l (x:es)
	|otherwise = maxVentas l (y:es)

--aux
numVentas :: Local -> Empleado -> Int
numVentas (L _ _ _) _ = 0
numVentas (Sancion _ _ l) e = numVentas l e
numVentas (VenderPedido p l) e 
	|atendioP p == e = 1 + numVentas l e
	|otherwise = numVentas l e

--aux
filtroPorCombo :: Local -> [Empleado] -> [Empleado]
filtroPorCombo l [] = []
filtroPorCombo l (e:es)
	|maxCombos l (empleadosL l) == numCombos l e = e:filtroPorCombo l es
	|otherwise = filtroPorCombo l es

--aux
maxCombos :: Local -> [Empleado] -> Int
maxCombos l (e:[]) = numCombos l e
maxCombos l (x:y:es)
	|numCombos l x >= numCombos l y = maxCombos l (x:es)
	|otherwise = maxCombos l (y:es)

--aux
numCombos :: Local -> Empleado -> Int
numCombos (L _ _ _) _ = 0
numCombos (Sancion _ _ l) e = numCombos l e
numCombos (VenderPedido p l) e
	|atendioP p == e = length (combosP p) + numCombos l e
	|otherwise = numCombos l e



sancionL :: Local -> Empleado -> Energia -> Local
sancionL (L bs hs es) empleado en = Sancion empleado en (L bs hs es)
sancionL (VenderPedido p l) empleado en = Sancion empleado en (VenderPedido p l)									
sancionL (Sancion e energia l) 
	empleado en = Sancion empleado en (Sancion e energia l)
			
anularPedidoL :: Local -> Int -> Local
anularPedidoL (L bs hs es) n = (L bs hs es)
anularPedidoL (VenderPedido p l) n
			|(numeroP p == n) && (elem (atendioP p) (empleadosL l) ) = l
			|otherwise = VenderPedido p (anularPedidoL l n)
anularPedidoL (Sancion empleado energia l) n = Sancion empleado energia (anularPedidoL l n)
			

agregarComboAlPedidoL :: Local -> Combo -> Int -> Local
agregarComboAlPedidoL (L bs hs es) combo n =  (L bs hs es)
agregarComboAlPedidoL (VenderPedido p l) combo n 
			|(numeroP p == n) && (hayStock l combo) && (empleadoPuedeAtender l (atendioP p) combo) = VenderPedido (agregarComboP p combo) l
			|otherwise = VenderPedido p (agregarComboAlPedidoL l combo n)
agregarComboAlPedidoL (Sancion empleado energia l) combo n = Sancion empleado energia (agregarComboAlPedidoL l combo n)

--Aux
hayStock :: Local -> Combo -> Bool
hayStock l combo = (stockBebidasL l (bebidaC combo) > 0 ) && (stockSandwichesL l (sandwichC combo) > 0)

--Aux
empleadoPuedeAtender :: Local -> Empleado -> Combo -> Bool
empleadoPuedeAtender local empleado combo = (elem empleado (empleadosL local)) && (energiaEmpleadoL local empleado >= dificultadC combo)

elVagonetaL :: Local -> Empleado
elVagonetaL l= elVagonetaAux (empleadosL l) l 

--Aux
elVagonetaAux :: [Empleado] -> Local -> Empleado
elVagonetaAux [e] local = e
elVagonetaAux (e:y:es) local
	|maxDescansoEmpleado1 >= maxDescansoEmpleado2 = elVagonetaAux (e:es) local
	|otherwise = elVagonetaAux (y:es) local

	where 	maxDescansoEmpleado1 = (maximoDescanso (listaDescansos (length (empleadosQueVendieron (ventasL local) (empleadosL local) (empleadosL local))) (listaPosVentas e (empleadosQueVendieron (ventasL local) (empleadosL local) (empleadosL local)) 0) (listaPosVentas e (empleadosQueVendieron (ventasL local) (empleadosL local) (empleadosL local) )0)))
		maxDescansoEmpleado2 = (maximoDescanso (listaDescansos (length (empleadosQueVendieron (ventasL local) (empleadosL local) (empleadosL local))) (listaPosVentas y (empleadosQueVendieron (ventasL local) (empleadosL local) (empleadosL local)) 0) (listaPosVentas y (empleadosQueVendieron (ventasL local) (empleadosL local) (empleadosL local) )0)))


--Aux
listaPosVentas :: Empleado -> [Empleado] -> Int -> [Int]
listaPosVentas empleado [] n = []
listaPosVentas empleado (e:es) n
        |empleado == e = n: listaPosVentas empleado es (n+1)
        |otherwise = listaPosVentas empleado es (n+1)
             
--Aux        
maximoDescanso :: [Int] -> Int
maximoDescanso [x] = x
maximoDescanso (x:xs)
        |x > maximoDescanso xs = x
        |otherwise = maximoDescanso xs        
--Aux                 
listaDescansos :: Int -> [Int] -> [Int] -> [Int]
listaDescansos n [] _ = [n]
listaDescansos n [x] lista = [head lista, n-x-1]
listaDescansos n (x:y:xs) lista = descansos (x:y:xs) n lista 

--Aux
descansos :: [Int] -> Int -> [Int] -> [Int]
descansos [x] n lista=  [head lista, n-x-1]
descansos (x:y:xs) n lista 
        |y - x == 1 =  0 : descansos (y:xs) n lista
        |otherwise = (y -x -1): descansos (y:xs) n lista



--Local, nuevoL, stockBebidasL, stockSandwichesL, bebidasDelLocalL, sandwichesDelLocalL,empleadosL, energiaEmpleadoL, desempleadosL, ventasL, unaVentaCadaUnoL, venderL,sancionL, candidatosAEmpleadosDelMesL, anularPedidoL, agregarComboAlPedidoL
--sancionL (Sancion "Cacho" 10 (VenderPedido (nuevoP 3 "Cacho" [(nuevoC Pesticola McPato 4),(nuevoC AguaConGags McPato 88),(nuevoC FalsaNaranja McGyver 3),(nuevoC AguaConGags McPato 5)])(L [(Pesticola,10),(FalsaNaranja,15)] [(McPato,12),(McGyver,4)] ["cacho","chocho","chido"]))) "Cacho" 10




--desempleadosL (venderL (Sancion "cacho" 10 (VenderPedido (nuevoP 3 "cacho" [(nuevoC Pesticola McPato 4),(nuevoC AguaConGags McPato 18),(nuevoC FalsaNaranja McGyver 3),(nuevoC AguaConGags McPato 5)])(L [(Pesticola,10),(FalsaNaranja,15)] [(McPato,12),(McGyver,4)] ["cacho","chocho","chido"]))) (nuevoP 3 "chocho" [(nuevoC Pesticola McGyver 4),(nuevoC AguaConGags McPato 8),(nuevoC FalsaNaranja McGyver 3),(nuevoC AguaConGags McPato 8)]))
